package gitlab

import (
	"fmt"
	"io"
	"os"
	"path/filepath"
	"time"

	"github.com/go-git/go-git/v5"
	"github.com/go-git/go-git/v5/plumbing"
	"github.com/go-git/go-git/v5/plumbing/object"
	"github.com/go-git/go-git/v5/plumbing/transport/http"
	"github.com/xanzy/go-gitlab"
)

type GitConfig struct {
	Username string `yaml:"username"`
	Password string `yaml:"password"`
}
type GitWorkSpace struct {
	WorkSpace  string
	Repository *git.Repository
	Auth       *http.BasicAuth
}
type GitWorkSpaceResult struct {
	GitWorkSpace *GitWorkSpace
	Err          error
}

// add a file  to  workspace/(rootbase)，to commit, to push
func (gw *GitWorkSpace) PushFileRootBaseCommit(source_file_path string, commit string) error {
	w, _ := gw.Repository.Worktree()
	filename := filepath.Base(source_file_path)
	dest := filepath.Join(gw.WorkSpace, source_file_path)
	copy(source_file_path, dest)
	w.Add(filename)
	if _, er := w.Commit(commit, &git.CommitOptions{
		Author: &object.Signature{
			Name:  gw.Auth.Username,
			Email: "wujianqiang@geniusafc.com",
			When:  time.Now()},
	}); er != nil {
		return er
	}
	return gw.Repository.Push(&git.PushOptions{
		Auth: gw.Auth,
	})
}

// name 是项目名称
func (gc *GitConfig) CreateWorkSpace(workdir string, addr string, branch string) *GitWorkSpaceResult {
	auth := &http.BasicAuth{
		Username: gc.Username,
		Password: gc.Password,
	}
	repository, er := git.PlainClone(workdir, false, &git.CloneOptions{
		URL:           addr,
		Progress:      os.Stdout,
		Auth:          auth,
		ReferenceName: plumbing.ReferenceName("refs/heads/" + branch),
	})
	if er != nil {
		return &GitWorkSpaceResult{GitWorkSpace: nil, Err: er}

	}

	return &GitWorkSpaceResult{
		GitWorkSpace: &GitWorkSpace{
			WorkSpace:  workdir,
			Repository: repository,
			Auth:       auth,
		}, Err: nil}
}

func copy(src, dst string) (int64, error) {
	sourceFileStat, err := os.Stat(src)
	if err != nil {
		return 0, err
	}

	if !sourceFileStat.Mode().IsRegular() {
		return 0, fmt.Errorf("%s is not a regular file", src)
	}

	source, err := os.Open(src)
	if err != nil {
		return 0, err
	}
	defer source.Close()

	destination, err := os.Create(dst)
	if err != nil {
		return 0, err
	}
	defer destination.Close()
	nBytes, err := io.Copy(destination, source)
	return nBytes, err
}

func ConnectGitlabByToken(token string, addr string) (*gitlab.Client, error) {
	return gitlab.NewClient(token, gitlab.WithBaseURL(addr))
}
func ConnectGitlabByAccount(username string, password string, addr string) (*gitlab.Client, error) {
	return gitlab.NewBasicAuthClient(username, password, gitlab.WithBaseURL(addr))
}
func GetUsers(client *gitlab.Client) ([]*gitlab.User, error) {
	users, _, err := client.Users.ListUsers(&gitlab.ListUsersOptions{})
	return users, err
}
func GetProjects(client *gitlab.Client) ([]*gitlab.Project, error) {
	pros, _, err := client.Projects.ListProjects(&gitlab.ListProjectsOptions{})
	return pros, err
}

func GetBranchesByProId(client *gitlab.Client, proid int) ([]*gitlab.Branch, error) {
	branches, _, er := client.Branches.ListBranches(proid, &gitlab.ListBranchesOptions{})
	return branches, er
}

func GetProById(client *gitlab.Client, proid int) (*gitlab.Project, error) {
	pro, _, er := client.Projects.GetProject(proid, &gitlab.GetProjectOptions{})
	return pro, er
}

func CreateMr(proid int, sourcebranch string, targetbranch string, title string, client *gitlab.Client) (*gitlab.MergeRequest, error) {
	mr, _, er := client.MergeRequests.CreateMergeRequest(proid, &gitlab.CreateMergeRequestOptions{
		SourceBranch: &sourcebranch,
		TargetBranch: &targetbranch,
		Title:        &title,
	})
	return mr, er
}

func AcceptMr(proid int, mr *gitlab.MergeRequest, client *gitlab.Client) error {
	_, _, mer := client.MergeRequests.AcceptMergeRequest(proid, mr.IID, &gitlab.AcceptMergeRequestOptions{})
	return mer

}
